
public abstract class AbstractClassifier {
    protected static class MessageIteratorWrapper {
  	  public static int DEFAULT_FOLD_COUNT = 1;
  	  
  	  private String dataFile;
  	  private int foldIndex;
  	  private int foldCount;
  	  private MessageIterator miPreTraining;
  	  private MessageIterator miTraining;
  	  private MessageIterator miTesting;
  	  private int indexTraining;
  	  private int indexPreTraining;
  	  private int indexTesting; 
  	  
  	  public MessageIteratorWrapper(String dataFile) throws Exception {
  		  this(dataFile, 0, DEFAULT_FOLD_COUNT);
  	  }
  	  public MessageIteratorWrapper(String dataFile, int foldIndex, int foldCount) throws Exception {
  		  this.dataFile = dataFile;
  		  this.foldIndex = foldIndex;
  		  this.foldCount = foldCount;
  		  this.miTraining = new MessageIterator(dataFile);
  		  this.miTesting = new MessageIterator(dataFile);
  		  this.miPreTraining = new MessageIterator(dataFile);
  		  
  		  this.indexPreTraining = 0;
  		  this.indexTraining = 0;
  		  this.indexTesting = 0;
  		  
  	  }
  	  
  	  public void initialize() throws Exception {
  		  this.miTraining = new MessageIterator(dataFile);
  		  this.miTesting = new MessageIterator(dataFile);
  		  this.miPreTraining = new MessageIterator(dataFile);
  		  
  		  this.indexPreTraining = 0;
  		  this.indexTraining = 0;
  		  this.indexTesting = 0;
  	  }
  	  
  	  public MessageFeatures getNextPreTrainingMessage() {
		  try {
			  if(foldCount > 1)
				  while(indexPreTraining++ % foldCount == foldIndex)
					  miPreTraining.getNextMessage();
			  
			  return miPreTraining.getNextMessage();
		  }catch (Exception e){
			  return null;
		  }
	  }
  	  
  	  public MessageFeatures getNextTrainingMessage() {
  		  try {
  			  if(foldCount > 1)
  				  while(indexTraining++ % foldCount == foldIndex)
  					  miTraining.getNextMessage();
  			  
  			  return miTraining.getNextMessage();
  		  }catch (Exception e){
  			  return null;
  		  }
  	  }
  	  
  	  public MessageFeatures getNextTestingMessage() {
  		  try {
  			  if(foldCount > 1)
  				  while(indexTesting++ % foldCount != foldIndex)
  					  miTesting.getNextMessage();
  			  
  			  return miTesting.getNextMessage();
  		  } catch (Exception e){
  			  return null;
  		  }
  	  }
    }
    
	protected int foldIndex;
	protected int foldCount;
	protected String dataFile;
	protected MessageIteratorWrapper miw;

	public AbstractClassifier(String dataFile) throws Exception{
		this.dataFile = dataFile;
	}
	
	public void initialize(int foldIndex, int foldCount) throws Exception
	{
		this.foldIndex = foldIndex;
		this.foldCount = foldCount;
		this.miw = new MessageIteratorWrapper(dataFile, foldIndex, foldCount);
	}
	
	public abstract void train() throws Exception;
	public abstract double test() throws Exception; //return accuracy
}
